package com.dukla.picbak.handler;

import com.drew.imaging.FileType;
import com.drew.imaging.FileTypeDetector;
import com.drew.imaging.avi.AviMetadataReader;
import com.drew.imaging.jpeg.JpegMetadataReader;
import com.drew.imaging.mp4.Mp4MetadataReader;
import com.drew.metadata.Directory;
import com.drew.metadata.Metadata;
import com.drew.metadata.Tag;
import com.drew.metadata.avi.AviDirectory;
import com.drew.metadata.exif.ExifSubIFDDirectory;
import com.drew.metadata.mp4.Mp4Directory;
import com.dukla.picbak.vo.MediaFileInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.io.*;
import java.nio.file.Files;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.Date;
import java.util.Objects;
import java.util.Iterator;

@Component
public class FileScanner {

    private final Logger logger =
            LoggerFactory.getLogger(FileScanner.class);

    @Value("${pic-backup.scan-path}")
    String scanPath;

    @Value("${pic-backup.mode}")
    String mode;

    @Value("${pic-backup.log-path}")
    String logPath;

    File logFile;

    BufferedWriter logFileWriter;

    @Autowired
    DataContainer dataContainer;

    private String bytes2HexString(byte[] bytes) {
        StringBuffer sb = new StringBuffer();
        if (bytes == null || bytes.length == 0) {
            return null;
        }
        for (byte aByte : bytes) {
            int v = aByte & 0xFF;
            String hv = Integer.toHexString(v);
            if (hv.length() < 2) {
                sb.append(0);
            }
            sb.append(hv);
        }
        return sb.toString();
    }

    public void start(){
        File readDir=new File(scanPath);
        String logFileName = new SimpleDateFormat("yyyyMMddhhmmss").format(new Date()) + ".txt";
        logFile = new File(logPath +"/scan-log-"+ logFileName);
        if(!readDir.exists() || !readDir.isDirectory()){
            logger.error("{} not exist or is not directory!",scanPath);
            return;
        }
        //打开日志文件写入
        try {
            logFileWriter = new BufferedWriter(new FileWriter(logFile));
        } catch (IOException e) {
            logger.error(e.getMessage(),e);
            return;
        }
        //递归扫描
        scanDir(readDir);
        //关闭日志文件写入
        try {
            logFileWriter.close();
        } catch (IOException e) {
            logger.error(e.getMessage(),e);
        }
    }

    /**
     * 递归遍历文件目录
     */
    private void scanDir(File readDir){
        for(File file: Objects.requireNonNull(readDir.listFiles())){
            if(file.isDirectory()){
                logger.info("scan {}",file.getAbsolutePath());
                scanDir(file);
            }else{
                process(file);
            }
        }
    }

    private void process(File file){
        try {
            FileType fileType = FileTypeDetector.detectFileType(new BufferedInputStream(Files.newInputStream(file.toPath())));
            //元数据
            Metadata meta;
            //媒体日期
            Date mediaDate;
            switch (fileType){
                case Jpeg:
                    meta=JpegMetadataReader.readMetadata(file);
                    mediaDate = getExifDate(meta);
                    break;
                case Mp4:
                    meta=Mp4MetadataReader.readMetadata(file);
                    mediaDate = getMp4Date(meta);
                    break;
                case Avi:
                    meta=AviMetadataReader.readMetadata(file);
                    mediaDate = getAviDate(meta);
                    break;
                default:
                    logger.info("{}-file:{},passed!",fileType.getName(),file.getName());
                    return;
            }
            logger.info("{} file,path={},date={}",fileType.getName(),file.getAbsolutePath(),mediaDate);
            //保留日志
            if("scan-log".equals(this.mode) || "save-log".equals(this.mode)){
                this.logToFile(file.getAbsolutePath(),mediaDate);
            }
            if(mediaDate==null){
                logger.warn("Media date is null,ignored!");
                return;
            }
            //只是保持扫描日志
            if("scan-log".equals(this.mode)){
                return;
            }
            //推送入库队列
            MediaFileInfo fileInfo=new MediaFileInfo();
            fileInfo.setFile(file);
            fileInfo.setMediaDate(mediaDate);
            this.dataContainer.putFileContentQueue(fileInfo);
        } catch (Exception e) {
            logger.error(e.getMessage(),e);
        }

    }

    /**
     * 扫描日志记录到文件
     */
    private void logToFile(String fileName,Date mediaDate){
        try {
            String scanTime = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(new Date());
            String mediaTime = mediaDate!=null ? new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(mediaDate) : "N/A";
            logFileWriter.append(scanTime).append(",").append(fileName).append(",").append(mediaTime);
            logFileWriter.newLine();
            logFileWriter.flush();
        } catch (Exception e) {
           logger.error(e.getMessage(),e);
        }
    }

    private Date getMp4Date(Metadata meta){
        //获取MP4目录
        Mp4Directory mp4Directory = meta.getFirstDirectoryOfType(Mp4Directory.class);
        Date date = null;
        if (mp4Directory != null) {
            //获取创建日期
            date = mp4Directory.getDate(Mp4Directory.TAG_CREATION_TIME);
            if (date != null) {
                return date;
            }
            //获取修改日期
            date = mp4Directory.getDate(Mp4Directory.TAG_MODIFICATION_TIME);
            if (date != null) {
                return date;
            }
        } else {
            logger.warn("No MP4 metadata found.");
        }
        return date;
    }

    private Date getAviDate(Metadata meta){
        //获取Avi目录
        AviDirectory aviDirectory = meta.getFirstDirectoryOfType(AviDirectory.class);
        Date date = null;
        if (aviDirectory != null) {
            //获取创建日期
            date = aviDirectory.getDate(AviDirectory.TAG_DATETIME_ORIGINAL);
            if (date != null) {
                return date;
            }
        } else {
            logger.warn("No AVI metadata found.");
        }
        return date;
    }

    private Date getExifDate(Metadata meta){
        //获取Exif目录
        ExifSubIFDDirectory exifSubIFDDirectory = meta.getFirstDirectoryOfType(ExifSubIFDDirectory.class);
        Date date = null;
        if (exifSubIFDDirectory != null) {
            //获取创建日期
            date = exifSubIFDDirectory.getDate(ExifSubIFDDirectory.TAG_DATETIME_ORIGINAL);
            if (date != null) {
                return date;
            }
            //获取修改日期
            date = exifSubIFDDirectory.getDate(ExifSubIFDDirectory.TAG_DATETIME);
            if (date != null) {
                return date;
            }
        } else {
            logger.warn("No Exif metadata found.");
        }
        return date;
//        Iterable<ExifSubIFDDirectory> directoryIterable = meta.getDirectoriesOfType(ExifSubIFDDirectory.class);
//        Iterator<ExifSubIFDDirectory> directoryIterator = directoryIterable.iterator();
//        while (directoryIterator.hasNext()) {
//            Directory directory = directoryIterator.next();
//            Collection<Tag> tags = directory.getTags();
//            for (Tag tag : tags) {
//                if(tag.getTagName().contains("Date/Time")){
//                    logger.info("name={},value={}",tag.getTagName(),tag.getDescription());
//                    String d=tag.getDescription().substring(0,9);
//                    SimpleDateFormat sdf=new SimpleDateFormat("yyyy:MM:dd");
//                    try {
//                        return sdf.parse(d);
//                    } catch (ParseException e) {
//                        logger.error(e.getMessage(),e);
//                        return null;
//                    }
//                }
//            }
//        }
//        return null;
    }


}
